package ac.github.oa.api

import ac.github.oa.OriginAttribute
import ac.github.oa.api.common.Matcher
import ac.github.oa.api.event.entity.EntityDamageEvent
import ac.github.oa.api.event.entity.EntityLoadEquipmentEvent
import ac.github.oa.api.event.item.ItemCreatedEvent
import ac.github.oa.api.event.item.ItemDurabilityDamageEvent
import ac.github.oa.api.event.item.ItemUpdateEvent
import ac.github.oa.internal.core.attribute.AttributeManager
import ac.github.oa.internal.core.attribute.equip.Hand
import ac.github.oa.internal.core.attribute.equip.OffHand
import ac.github.oa.internal.core.item.ItemInstance
import ac.github.oa.internal.core.item.ItemPlant
import ac.github.oa.internal.core.item.generator.SourceGenerator
import org.bukkit.Material
import org.bukkit.entity.Player
import org.bukkit.inventory.Inventory
import org.bukkit.inventory.ItemStack
import taboolib.common.platform.event.EventPriority
import taboolib.common.platform.event.SubscribeEvent
import taboolib.common5.Coerce
import taboolib.module.nms.ItemTagData
import taboolib.module.nms.getItemTag
import taboolib.platform.util.isAir
import taboolib.platform.util.modifyLore
import kotlin.math.max
import kotlin.math.min

object ItemAPI {

    val durabilityChar: Char
        get() = OriginAttribute.config.getString("options.durability-char", "/")!!.toCharArray()[0]

    val durabilityKeyword: String
        get() = OriginAttribute.config.getString("options.durability")!!

    private val damageRemove: Boolean
        get() = OriginAttribute.config.getBoolean("options.damage-remove")

    private val isReadNBT: Boolean
        get() = OriginAttribute.config.getBoolean("options.read-nbt")

    /**
     * 保留旧耐久
     */
//    @SubscribeEvent
//    fun e(e: ItemUpdateEvent) {
//        val newItemStack = e.newItemStack
//        val oldItemStack = e.oldItemStack
//
//        // 如果武器存在耐久节点
//        if (e.item.config.contains("nbt.${NBT.MAX_DURABILITY.key}")) {
//            val max = e.item.config.getInt("nbt.${NBT.MAX_DURABILITY.key}")
//            val durability = getDurability(oldItemStack)
//            setDurability(newItemStack, durability)
//            ItemDurabilityDamageEvent(e.player, newItemStack, max, max, durability).call()
//        }
//    }

    /**
     * 渲染装备战斗力
     */
    @SubscribeEvent
    fun e(e: ItemCreatedEvent) {
        if (e.generator is SourceGenerator) {
            val itemStack = e.itemStack
            val attributeData = OriginAttributeAPI.loadList(itemStack.itemMeta?.lore ?: emptyList())
            attributeData.autoCombatPower()
            val result = Coerce.toInteger(attributeData.combatPower).toString()
            itemStack.modifyLore {
                this.forEachIndexed { index, s ->
                    this[index] = s.replace("%combat-power%", result)
                }
            }
            itemStack.updateDurability()
        }
    }

//    @SubscribeEvent
//    fun e0(e: ItemDurabilityDamageEvent) {
//        val itemStack = e.itemStack
//        val durability = getDurability(itemStack)
//        if (durability <= 0) {
//            ItemPlant.parseItem(itemStack) ?: return
//            itemStack.amount = 0
//        }
//    }

    @SubscribeEvent(ignoreCancelled = true, priority = EventPriority.MONITOR)
    fun e(e: EntityDamageEvent) {
        if (e.isPre) return
        // 扣除攻击者的主手副手耐久
        (e.attacker as? Player)?.let { player ->
            AttributeManager.get(player).getItems(true) { slot is Hand || slot is OffHand }.forEach {
                it.item.takeDurability(player, 1, e)
            }
        }
        // 扣除被攻击者的身体物品耐久
        (e.victim as? Player)?.let { player ->
            e.damageMemory.victimData.getItems(true) { slot !is Hand }.forEach {
                // 减少主手盾的防御
                it.item.takeDurability(player, 1, e)
            }
        }
    }

    @SubscribeEvent(ignoreCancelled = true)
    fun e(e: EntityLoadEquipmentEvent.Render) {
        if (isReadNBT) {
            val items = e.attributeData.items
            val listOf = mutableListOf<String>()
            // 从NBT内获取属性
            items.filter { it.enable }.forEach {
                it.item.getItemTag()["attributes"]?.asList()?.forEach {
                    listOf += it.asString()
                }
            }
            // 载入属性
            e.attributeData.merge(OriginAttributeAPI.loadList(e.entity, listOf))
        }

    }

    fun checkUpdate(player: Player, inventory: Inventory) {
        (0 until inventory.size).forEach { i ->
            val item = inventory.getItem(i)
            if (item.isAir()) {
                return@forEach
            }
            val canUpdate = item.canUpdate()
            if (canUpdate) {
                val itemInstance = ItemInstance.get(item)!!
                val event = ItemUpdateEvent(player, item, itemInstance.rebuild(player), itemInstance.item)
                event.call()
                inventory.setItem(i, event.newItemStack)
            }
        }
    }

    fun ItemStack.canUpdate(): Boolean {
        val item = ItemPlant.parseItem(this) ?: return false
        if (!item.isUpdate) return false
        val itemTag = this.getItemTag()
        val asLong = itemTag["oa-hasCode"]?.asInt() ?: 0
        return asLong != item.hasCode
    }


    fun ItemStack.takeDurability(player: Player? = null, value: Int = 1, source: Any? = null) {
        if (this.type == Material.AIR) return
        val itemTag = getItemTag()
        if (itemTag.containsKey(NBT.MAX_DURABILITY.key)) {
            val max = itemTag[NBT.MAX_DURABILITY.key]!!.asInt()
            val old = itemTag[NBT.DURABILITY.key]?.asInt() ?: max
            val event = ItemDurabilityDamageEvent.Pre(player, this, max, old, value, source)
            if (event.call()) {
                val durability = (old - event.value).coerceAtLeast(0).coerceAtMost(max)
                if (durability == 0 && damageRemove) {
                    this.amount = 0
                } else {
                    itemTag[NBT.DURABILITY.key] = ItemTagData(durability)
                    itemTag.saveTo(this)
                    this.updateDurability(max, durability)
                    ItemDurabilityDamageEvent.Post(player, this, max, old, durability, source).call()
                }
            }
        }
    }

    fun getMaxDurability(itemStack: ItemStack): Int {
        val itemTag = itemStack.getItemTag()
        return itemTag[NBT.MAX_DURABILITY.key]?.asInt() ?: -1;
    }

    fun getDurability(itemStack: ItemStack): Int {
        val itemTag = itemStack.getItemTag()
        if (itemTag.containsKey(NBT.MAX_DURABILITY.key)) {
            val maxDurability = itemTag[NBT.MAX_DURABILITY.key]!!.asInt()
            return (itemTag[NBT.DURABILITY.key]?.asInt() ?: maxDurability)
        }
        return -1;
    }

    fun setDurability(itemStack: ItemStack, value: Int, max: Int) {
        val itemTag = itemStack.getItemTag()
        if (itemTag.containsKey(NBT.MAX_DURABILITY.key)) {
            itemTag[NBT.MAX_DURABILITY.key] = ItemTagData(max)
            val maxDurability = itemTag[NBT.MAX_DURABILITY.key]!!.asInt()
            val min = min(max(value, 0), maxDurability)
            itemTag[NBT.DURABILITY.key] = ItemTagData(min)
            itemTag.saveTo(itemStack)
            itemStack.updateDurability(maxDurability, min)
            itemStack.modifyLore {
                this.forEachIndexed { index, s ->
                    if (s.contains(durabilityKeyword) && s.contains(durabilityChar)) {
                        val matcher = Matcher.range(s, durabilityChar.toString())
                        this[index] = s.replaceFirst(matcher.pos1.toInt().toString(), min.toString())
                            .replace(matcher.pos2.toInt().toString(), min.toString())
                    }
                }
            }
        }
    }

    fun ItemStack.updateDurability() {
        val itemTag = getItemTag()
        if (itemTag.containsKey(NBT.MAX_DURABILITY.key)) {
            val maxDurability = itemTag[NBT.MAX_DURABILITY.key]!!.asInt()
            val durability = (itemTag[NBT.DURABILITY.key]?.asInt() ?: maxDurability)
            updateDurability(maxDurability, durability)
        }
    }

    private fun ItemStack.updateDurability(max: Int, current: Int) {
        // 当前耐久 / 最大耐久 得到耐久百分比
        val percent = Coerce.toDouble(current) / Coerce.toDouble(max)
        val durability = type.maxDurability
        // 原版物品最大耐久 = 最大耐久*百分比
        this.durability = Coerce.toShort(durability - Coerce.toDouble(durability) * percent)
        modifyLore {
            this.forEachIndexed { index, s ->
                if (s.contains(durabilityKeyword) && s.contains(durabilityChar)) {
                    val matcher = Matcher.range(s, durabilityChar.toString())
                    this[index] = s.replaceFirst(matcher.pos1.toInt().toString(), current.toString())
                        .replace(matcher.pos2.toInt().toString(), max.toString())
                }
            }

        }
    }


}
